#ifndef _VECTOR_H_
#define _VECTOR_H_

#include <string>
#include <math.h>
#include "misc.h"

typedef float real;

class Matrix4f;

class Vector4f{

	friend class Matrix4f;

private:
	real _x;
	real _y;
	real _z;
	real _w;
	
public:
	Vector4f()
	{
		_x = 0.0f;
		_y = 0.0f;
		_z = 0.0f;
		_w = 0.0f;
	}
	
	Vector4f(real x, real y, real z, real w)
	{
		_x = x;
		_y = y;
		_z = z;
		_w = w;
	}
	
	~Vector4f()
	{
	}
	
	inline void Set(real x, real y, real z, real w)
	{
		_x = x;
		_y = y;
		_z = z;
		_w = w;
	}
	
	inline void SetX(real x)
	{
		_x = x;
	}
	
	inline void SetY(real y)
	{
		_y = y;
	}
	
	inline void SetZ(real z)
	{
		_z = z;
	}
	
	inline void SetW(real w)
	{
		_w = w;
	}
	
	inline void AddX(real x)
	{
		_x += x;
	}
	
	inline void AddY(real y)
	{
		_y += y;
	}
	
	inline void AddZ(real z)
	{
		_z += z;
	}
	
	inline void AddW(real w)
	{
		_w += w;
	}
	
	inline real GetX() const { return _x; }

	inline real GetY() const { return _y; }

	inline real GetZ() const { return _z; }

	inline real GetW() const { return _w; }	
	
	inline Vector4f Add(const Vector4f& v) const
	{
		Vector4f r(	_x + v._x,
								_y + v._y,
								_z + v._z,
								_w + v._w 
							);
		return r;
	}
	
	inline Vector4f Sub(const Vector4f& v) const
	{
		Vector4f r(	_x - v._x,
								_y - v._y,
								_z - v._z,
								_w - v._w 
							);
		return r;
	}
	
	inline Vector4f Mul(real c) const
	{
		Vector4f r(	_x * c,
								_y * c,
								_z * c,
								_w * c 
							);
		return r;		
	}
	
	inline Vector4f Mul(const Vector4f& v) const
	{
		Vector4f r(	_x * v._x,
								_y * v._y,
								_z * v._z,
								_w * v._w 
							);
		return r;		
	}
	
	inline Vector4f Div(real c) const
	{
		Vector4f r(	_x / c,
								_y / c,
								_z / c,
								_w / c 
							);
		return r;		
	}
	
	inline Vector4f Div(const Vector4f& v) const
	{
		Vector4f r(	_x / v._x,
								_y / v._y,
								_z / v._z,
								_w / v._w 
							);
		return r;		
	}
	
	inline real GetLength() const
	{
		return sqrt( _x * _x + _y * _y + _z * _z + _w * _w);
	}
	
	inline void Normalize()
	{
		real len = GetLength();
		if(len > 0)
		{
			_x = _x / len;
			_y = _y / len;
			_z = _z / len;
			_w = _w / len;
		}		
	}
	
	inline Vector4f GetNormalized() const
	{
		Vector4f r = *this;
		r.Normalize();
		return r;		
	}
	
	inline real Dot(const Vector4f & v) const
	{
		return (_x * v._x) + (_y * v._y) + (_z * v._z) + (_w * v._w);
	}	
	
	inline Vector4f Cross(const Vector4f & v) const
	{
		Vector4f r;
		
		r._x = (_y * v._z) - (_z * v._y);
		r._y = (_z * v._x) - (_x * v._z);
		r._z = (_x * v._y) - (_y * v._x);
		r._w = 0;
		
		return r;
	}
	
	inline std::string ToString() const
	{
		std::string s = "[ ";
		s = s + To_String<real>(_x) + "\n  " + To_String<real>(_y) + "\n  ";
		s = s + To_String<real>(_z) +"\n  " + To_String<real>(_w) + " ]\n";
		return s;
	}	

};

inline Vector4f operator+ (const Vector4f & l, const Vector4f & r) 	
{
	return l.Add(r);
}

inline Vector4f operator- (const Vector4f & l, const Vector4f & r) 	
{
	return l.Sub(r);
}

inline Vector4f operator* (const Vector4f & l, const Vector4f & r) 	
{
	return l.Mul(r);
}

inline Vector4f operator* (const Vector4f & l, const real r) 	
{
	return l.Mul(r);
}

inline Vector4f operator* (const real l, const Vector4f & r) 	
{
	return r.Mul(l);
}

inline Vector4f operator/ (const Vector4f & l, const Vector4f & r) 	
{
	return l.Div(r);
}

inline Vector4f operator/ (const Vector4f & l, const real r) 	
{
	return l.Div(r);
}

inline Vector4f operator/ (const real l, const Vector4f & r) 	
{
	return r.Div(l);
}


#endif
